﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.Linq;
using Win32;
using Microsoft.Win32;
using System.IO;

namespace SoundMixer
{
    public partial class Mixer : Form
    {
        #region Ctor
        public Mixer()
        {
            InitializeComponent();
        }
        private void OnLoad(object sender, EventArgs e)
        {
            this.MinimumSize = this.Size;
            this.MaximumSize = this.Size;

            cb_D_List.AddRange(
                new CheckBox[] { checkBox1, checkBox2, checkBox3, checkBox4, checkBox5, checkBox6, checkBox7, checkBox8, checkBox9, checkBox10 });
            tb_D_List.AddRange(
                new TrackBar[] { trackBar1, trackBar2, trackBar3, trackBar4, trackBar5, trackBar6, trackBar7, trackBar8, trackBar9, trackBar10 });
            lb_D_List.AddRange(
                new Label[] { label1, label2, label3, label4, label5, label6, label7, label8, label9, label10 });

            cb_S_List.AddRange(
                new CheckBox[] { checkBox11, checkBox12, checkBox13, checkBox14, checkBox15, checkBox16, checkBox17, checkBox18, checkBox19, checkBox20 });
            tb_S_List.AddRange(
                new TrackBar[] { trackBar11, trackBar12, trackBar13, trackBar14, trackBar15, trackBar16, trackBar17, trackBar18, trackBar19, trackBar20 });
            lb_S_List.AddRange(
                new Label[] { label11, label12, label13, label14, label15, label16, label17, label18, label19, label20 });

            var bEnum = tabControl1.Controls[0].Controls.GetEnumerator();
            while (bEnum.MoveNext())
            {
                if (bEnum.Current is Panel)
                {
                    var pEnum = (bEnum.Current as Panel).Controls.GetEnumerator();
                    while (pEnum.MoveNext())
                    {
                        if (pEnum.Current is Label)
                        {
                            (pEnum.Current as Control).Text = null;
                        }
                    }
                }
            }

            bool useXP = (isVista == false);

            {
                if (Process.GetCurrentProcess().MainModule.FileName == Application.ExecutablePath)
                {
                    RegistryKey key = Registry.CurrentUser.CreateSubKey(
                        string.Format(@"Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"));
                    if (key != null)
                    {
                        object value = key.GetValue(Application.ExecutablePath);
                        if (value != null &&
                            value.ToString().StartsWith("WINXP") &&
                            MessageBox.Show("Use XP Api ? { it may Cause unexpected behavware }", "Compatible mode detected .!.", MessageBoxButtons.OKCancel) == DialogResult.OK)
                        {
                            useXP = true;
                        }
                        else if (value != null)
                        {
                            // hmmm maybe Not .!.
                            //key.DeleteValue(Application.ExecutablePath);
                        }
                    }
                }
            }

            switch (useXP)
            {
                case true:
                    {
                        mode = Mode.XP;
                        wtfHandler = HandleInvoke;
                        GetLines();
                    }
                    break;

                case false:
                    {
                        mode = Mode.Vista;
                        Init();

                        //
                        // bug Fix
                        //
                        // it i catch the first session.
                        // [ Direct call to Init(...) ]
                        // i can catch the wrong session.
                        // somthing  that i dont want.
                        // [WMP, IE]
                        //
                        // it i catch the last session.
                        // [ThreadPool(Init, Object)]
                        // some ChangeState event fail to run.
                        //
                        // so change the volume will trigger
                        // volumeChange event and
                        // i can handle it from there.
                        //

                        ThreadPool.QueueUserWorkItem(
                            delegate
                            {
                                while (true)
                                {
                                    // start
                                    Vista.AudioSessionState state;
                                    var sList = sessionList.Where(x =>
                                    {
                                        x.GetState(out state);
                                        return
                                            state == Vista.AudioSessionState.AudioSessionStateExpired ||
                                            state == Vista.AudioSessionState.AudioSessionStateInactive;
                                    }).ToArray();

                                    Array.ForEach(sList, delegate(Vista.IAudioSessionControl session)
                                    {
                                        float pfLevel;
                                        Guid guid = Guid.Empty;
                                        (session as Vista.ISimpleAudioVolume).GetMasterVolume(out pfLevel);
                                        (session as Vista.ISimpleAudioVolume).SetMasterVolume(pfLevel, ref guid);
                                    });
                                    // end

                                    Thread.Sleep(2500);
                                }
                            });
                    }
                    break;
            }
        }
        private void OnClose(object sender, FormClosingEventArgs e)
        {
            if (isVista == false)
            {
                foreach (var item in deviceMixer.Keys)
                {
                    XP.Api.mixerClose(item);
                }
            }
        }
        #endregion     
        #region Properties
        object PidCheck = new object();

        volatile bool dLock = false;
        volatile object dObject = new object();
        volatile List<int> Taken_D = new List<int>();
        volatile List<TrackBar> tb_D_List = new List<TrackBar>();
        volatile List<CheckBox> cb_D_List = new List<CheckBox>();
        volatile List<Label> lb_D_List = new List<Label>();

        volatile bool sLock = false;
        volatile object sObject = new object();
        volatile List<int> Taken_S = new List<int>();
        volatile List<TrackBar> tb_S_List = new List<TrackBar>();
        volatile List<CheckBox> cb_S_List = new List<CheckBox>();
        volatile List<Label> lb_S_List = new List<Label>();

        public bool isVista
        {
            get
            {
                return Environment.OSVersion.Version.Major >= 6;
            }
        }

        enum Mode
        {
            Vista,
            XP,
            None
        }

        Mode mode = Mode.None;
        #endregion
        #region Events
        /* Device */
        private void dValueChanged(object sender, EventArgs e)
        {
            if (dLock)
                return;

            switch (mode)
            {
                case Mode.Vista:
                    {
                        try
                        {
                            #region Vista
                            int index = 0;
                            bool found = false;
                            int value = (sender as TrackBar).Value;
                            object tag = (sender as TrackBar).Tag;

                            for (int i = 0; i < volumeList.Capacity - 1; i++)
                            {
                                if (volumeList[i] == (sender as TrackBar).Tag)
                                {
                                    index = i;
                                    found = true;
                                    break;
                                }
                            }

                            if (found)
                            {
                                volumeList[index].SetMasterVolumeLevelScalar(value / 100.0f, Guid.Empty);
                            }
                            #endregion
                        }
                        catch (Exception)
                        {
                            //throw;
                        }
                    }
                    break;

                case Mode.XP:
                    try
                    {
                        // to many calls can cause Crash
                        //Thread.Sleep(30);

                        #region XP
                        int value = (sender as TrackBar).Value;
                        XP.Structs.MIXERLINE LINE = (XP.Structs.MIXERLINE)((sender as TrackBar).Tag);

                        foreach (var _key in deviceMixer.Keys)
                        {
                            foreach (var _value in deviceMixer[_key])
                            {
                                XP.Structs.MIXERLINE SOURCE = (XP.Structs.MIXERLINE)((sender as TrackBar).Tag);
                                XP.Structs.MIXERLINE TARGET = _value;

                                if (SOURCE.szShortName == TARGET.szShortName &&
                                    SOURCE.tTarget.szPname == TARGET.tTarget.szPname &&
                                    SOURCE.dwComponentType == TARGET.dwComponentType)
                                {
                                    // START

                                    IntPtr hMixer = _key;
                                    XP.Structs.MIXERLINECONTROLS CONTROL;
                                    XP.Structs.MIXERCONTROL[] MIXER;
                                    XP.Structs.MIXERCONTROLDETAILS DETAILS;

                                    if (GetControl(hMixer, LINE, out CONTROL) &&
                                        GetMixer(hMixer, CONTROL, out MIXER))
                                    {
                                        for (int i = 0; i < MIXER.Length; i++)
                                        {
                                            if (MIXER[i].szShortName == "Master Volume" ||
                                                MIXER[i].szShortName == "Volume")
                                            {
                                                if (SetDetails(
                                                    value, value,
                                                    hMixer, LINE, MIXER[i], out DETAILS))
                                                {
                                                    return;
                                                }

                                                break;
                                            }
                                        }
                                    }

                                    break;

                                    //END
                                }
                            }
                        }
                        #endregion
                    }
                    catch (Exception)
                    {
                        //throw;
                    }

                    {
                        //
                        // will be added later
                        //

                        /*
                        dLock = true;
                        (sender as TrackBar).Value = LastVal.....
                        dLock = false;
                         */
                    }
                    break;
            }
        }
        private void dCheck(object sender, EventArgs e)
        {
            if (dLock)
                return;

            switch (mode)
            {
                case Mode.Vista:
                    {
                        try
                        {
                            #region Vista
                            int index = 0;
                            bool found = false;
                            object tag = (sender as CheckBox).Tag;

                            for (int i = 0; i < volumeList.Capacity - 1; i++)
                            {
                                if (volumeList[i] == (sender as CheckBox).Tag)
                                {
                                    index = i;
                                    found = true;
                                    break;
                                }
                            }

                            switch ((sender as CheckBox).Checked)
                            {
                                case true:
                                    {
                                        if (found)
                                        {
                                            volumeList[index].SetMute(true, Guid.Empty);
                                        }
                                    }
                                    break;

                                case false:
                                    {
                                        if (found)
                                        {
                                            volumeList[index].SetMute(false, Guid.Empty);
                                        }
                                    }
                                    break;
                            }
                            #endregion
                        }
                        catch (Exception)
                        { 
                            //throw;
                        }
                    }
                    break;

                case Mode.XP:
                    try
                    {
                        // to many calls can cause Crash
                        //Thread.Sleep(30);

                        #region XP
                        bool value = (sender as CheckBox).Checked;
                        XP.Structs.MIXERLINE LINE = (XP.Structs.MIXERLINE)((sender as CheckBox).Tag);

                        foreach (var _key in deviceMixer.Keys)
                        {
                            foreach (var _value in deviceMixer[_key])
                            {
                                XP.Structs.MIXERLINE SOURCE = LINE;
                                XP.Structs.MIXERLINE TARGET = _value;

                                if (SOURCE.szShortName == TARGET.szShortName &&
                                    SOURCE.tTarget.szPname == TARGET.tTarget.szPname &&
                                    SOURCE.dwComponentType == TARGET.dwComponentType)
                                {
                                    // START

                                    IntPtr hMixer = _key;
                                    XP.Structs.MIXERLINECONTROLS CONTROL;
                                    XP.Structs.MIXERCONTROL[] MIXER;
                                    XP.Structs.MIXERCONTROLDETAILS DETAILS;

                                    if (GetControl(hMixer, LINE, out CONTROL) &&
                                        GetMixer(hMixer, CONTROL, out MIXER))
                                    {
                                        for (int i = 0; i < MIXER.Length; i++)
                                        {
                                            if (MIXER[i].szShortName == "Master Mute" ||
                                                    MIXER[i].szShortName == "Mute")
                                            {
                                                int operation = (value == true) ? 1 : 0;
                                                if (SetDetails(
                                                    operation, operation,
                                                    hMixer, LINE, MIXER[i], out DETAILS))
                                                {
                                                    return;
                                                }

                                                break;
                                            }
                                        }
                                    }

                                    break;

                                    //END
                                }
                            }
                        }
                        #endregion
                    }
                    catch (Exception)
                    {
                        //throw;
                    }

                    {
                        //
                        // will be added later
                        //

                        /*
                        dLock = true;
                        (sender as CheckBox).Checked = !(sender as CheckBox).Checked;
                        dLock = false;
                         */
                    }

                    break;
            }
        }

        /* Session */
        private void sValueChanged(object sender, EventArgs e)
        {
            if (sLock)
                return;

            try
            {
                int index = 0;
                bool found = false;
                Guid guid = Guid.Empty;
                object tag = (sender as TrackBar).Tag;
                float fLevel = (sender as TrackBar).Value / 100f;

                for (int i = 0; i < volumeList.Capacity - 1; i++)
                {
                    if (sessionList[i] == (sender as TrackBar).Tag)
                    {
                        index = i;
                        found = true;
                        break;
                    }
                }

                if (found)
                {
                    (sessionList[index] as Vista.ISimpleAudioVolume).SetMasterVolume(fLevel, ref guid);
                }
            }
            catch (Exception)
            {
                //throw;
            }
        }
        private void sCheck(object sender, EventArgs e)
        {
            if (sLock)
                return;

            try
            {
                bool isMute;
                int index = 0;
                int result = 0;
                bool found = false;
                Guid guid = Guid.Empty;
                object tag = (sender as CheckBox).Tag;

                for (int i = 0; i < volumeList.Capacity - 1; i++)
                {
                    if (sessionList[i] == (sender as CheckBox).Tag)
                    {
                        index = i;
                        found = true;
                        break;
                    }
                }

                switch ((sender as CheckBox).Checked)
                {
                    case true:
                        {
                            {
                                if (found)
                                {
                                    (sessionList[index] as Vista.ISimpleAudioVolume).GetMute(out isMute);

                                    if (!isMute)
                                    {
                                        result = (sessionList[index] as Vista.ISimpleAudioVolume).SetMute(true, ref guid);
                                    }
                                }
                            }
                        }
                        break;

                    case false:
                        {
                            {
                                if (found)
                                {
                                    (sessionList[index] as Vista.ISimpleAudioVolume).GetMute(out isMute);

                                    if (isMute)
                                    {
                                        result = (sessionList[index] as Vista.ISimpleAudioVolume).SetMute(false, ref guid);
                                    }
                                }
                            }
                        }
                        break;
                }
            }
            catch (Exception)
            {
                //throw;
            }
        }
        #endregion

        #region XP :: Properties
        volatile object GetSetObject = new object();
        volatile object messegeObject = new object();

        volatile Dictionary<IntPtr, XP.Structs.MIXERCAPS> deviceInfo =
            new Dictionary<IntPtr, XP.Structs.MIXERCAPS>();
        volatile Dictionary<IntPtr, XP.Structs.MIXERLINE[]> deviceMixer =
            new Dictionary<IntPtr, XP.Structs.MIXERLINE[]>();

        delegate void WTF(
            XP.Structs.MIXERLINE LINE,
            XP.Structs.MIXERCONTROL MIXER,
            XP.Structs.MIXERCONTROLDETAILS DETAILS,
            int[] result);
        WTF wtfHandler;

        #endregion
        #region XP :: Function
        // load [all] MIXERLINE[]
        void GetLines()
        {
            deviceInfo.Clear();
            deviceMixer.Clear();

            int count = 0;
            IntPtr hMixer = IntPtr.Zero;
            int NumDevs = XP.Api.mixerGetNumDevs();

            ///////////////////////
            ///  FIND ALL KEYs  ///
            ///////////////////////

            for (int index = 0; index < NumDevs; index++)
            {
                // properties
                XP.Structs.MIXERCAPS CAPS = new XP.Structs.MIXERCAPS();
                XP.Structs.MIXERLINE LINE = new XP.Structs.MIXERLINE()
                {
                    dwSource = 0,
                    dwDestination = -1,     // will be used later
                    cbStruct = Marshal.SizeOf(typeof(XP.Structs.MIXERLINE))
                };

                // open device and get Info
                if (XP.Api.mixerGetDevCaps(index, ref CAPS, Marshal.SizeOf(typeof(XP.Structs.MIXERCAPS))) == 0 &&
                    XP.Api.mixerOpen(out hMixer, index, base.Handle, IntPtr.Zero, XP.Enums.mixerOpenFlags.CALLBACK_WINDOW) == 0)
                {
                    // reset Cpunter
                    count = 0;

                    //
                    // [Ugly] way >> By Type
                    //

                    /*
                    // enum all possible COMPONENTTYPE to find main device
                    foreach (var item in Enum.GetNames(typeof(XP.Enums.COMPONENTTYPE)))
                    {
                        LINE.dwComponentType = (XP.Enums.COMPONENTTYPE)Enum.Parse(typeof(XP.Enums.COMPONENTTYPE), item);
                        if (XP.Api.mixerGetLineInfo(hMixer, ref LINE, XP.Enums.LineInfoFlags.MIXER_GETLINEINFOF_COMPONENTTYPE) == 0)
                        {
                            if (LINE.cConnections > 0 &&
                                count < LINE.cConnections)
                            {
                                count = LINE.cConnections;
                                break;
                            }

                            //break;
                        }
                    }
                     */

                    //
                    // [Cool] way >> By Destination
                    //

                    do
                    {
                        // adjust [dwDestination]
                        LINE.dwDestination++;

                        // enum all possible [cDestinations] >> [cConnections]
                        if (XP.Api.mixerGetLineInfo(hMixer, ref LINE, XP.Enums.lineInfoFlags.MIXER_GETLINEINFOF_DESTINATION) == 0)
                        {
                            if (LINE.cConnections > 0 &&
                                count < LINE.cConnections)
                            {
                                count = LINE.cConnections;
                            }
                        }
                    } while (LINE.dwDestination + 1 < CAPS.cDestinations);

                    // check if we got somthing ?!.
                    if (count <= 0)
                    {
                        XP.Api.mixerClose(hMixer);
                        continue;
                    }

                    // save details.
                    deviceInfo.Add(hMixer, CAPS);
                    deviceMixer.Add(hMixer, new XP.Structs.MIXERLINE[count + 1]);
                    deviceMixer[hMixer][0] = LINE;

                    // extract all conncetion
                    for (int i = 0; i < count; i++)
                    {
                        LINE = new XP.Structs.MIXERLINE()
                        {
                            dwSource = i,
                            dwDestination = LINE.dwDestination,
                            cbStruct = Marshal.SizeOf(typeof(XP.Structs.MIXERLINE))
                        };
                        if (XP.Api.mixerGetLineInfo(hMixer, ref LINE, XP.Enums.lineInfoFlags.MIXER_GETLINEINFOF_SOURCE) == 0)
                        {
                            deviceMixer[hMixer][i + 1] = LINE;
                        }
                    }

                    logBox.AppendText( string.Format("Device [Add] :: {0}\n", hMixer));
                    logBox.AppendText(string.Format("Lines :: {0}\n", count + 1));
                    logBox.AppendText(string.Format("Info :: {0}\n", CAPS.szPname));
                    logBox.AppendText(string.Format("---- ---- ---- ----\n"));

                    for (int i = 0; i < deviceMixer[hMixer].Count(); i++)
                    {
                        logBox.AppendText(string.Format("Index :: {0}\n", i));
                        logBox.AppendText(string.Format("Component Type :: {0}\n", deviceMixer[hMixer][i].dwComponentType));
                        logBox.AppendText(string.Format("Source :: {0}\n", deviceMixer[hMixer][i].dwSource));
                        logBox.AppendText(string.Format("Line :: {0}\n", deviceMixer[hMixer][i].fdwLine));
                        logBox.AppendText(string.Format("Name :: {0}\n", deviceMixer[hMixer][i].szName));
                        logBox.AppendText(string.Format("Short Name :: {0}\n", deviceMixer[hMixer][i].szShortName));
                        logBox.AppendText(string.Format("---- ---- ---- ----\n"));
                    }
                }
            }

            ///////////////////////
            ///  ENUM ALL KEYs  ///
            ///////////////////////

            foreach (var key in deviceMixer.Keys)
            {
                //catch only ?Volume [PlayBack] and Recording Contr [RecordingControl]
                // they are the main device for playback and recording
                // without that filter wecan catch MixerLine[] for many devices.
                // so Grab ther main Device volume its 'fine'

                int index = 0;
                bool found = false;
                XP.Structs.MIXERLINE value = deviceMixer[key][0];

                for (index = 0; index < tb_D_List.Count; index++)
                {
                    if (!Taken_D.Contains(index) &&
                        tb_D_List[index].Enabled == false)
                    {
                        found = true;
                        break;
                    }
                }

                if (found)
                {
                    int pfLevel = 0;
                    bool bMute = false;

                    bool
                        haveVol = false,
                        haveMute = false;

                    #region Find
                    XP.Structs.MIXERLINE LINE = value;
                    XP.Structs.MIXERLINECONTROLS CONTROL;
                    XP.Structs.MIXERCONTROL[] MIXER;
                    XP.Structs.MIXERCONTROLDETAILS DETAILS;

                    if (GetControl(hMixer, LINE, out CONTROL) &&
                        GetMixer(hMixer, CONTROL, out MIXER))
                    {
                        for (int i = 0; i < MIXER.Length; i++)
                        {
                            switch (MIXER[i].szShortName)
                            {
                                case "Volume":          // Vista
                                case "Master Volume":   // XP
                                    {
                                        if ((MIXER[i].szShortName == "Master Volume" ||
                                            MIXER[i].szShortName == "Volume") &&
                                            GetDetails(hMixer,LINE, MIXER[i], out DETAILS))
                                        {
                                            // because we have 2 sides
                                            // we have to find the bigger one,
                                            // he hold the real volume.

                                            if (DETAILS.paDetails == IntPtr.Zero)
                                                break;

                                            for (int blat = 0; blat < DETAILS.cChannels; blat++)
                                            {
                                                haveVol = true;
                                                int vol = Marshal.ReadInt32((IntPtr)((long)DETAILS.paDetails + (blat * 4)));
                                                if (pfLevel < vol) pfLevel = vol;
                                            }
                                        }
                                    }
                                    break;

                                case "Mute":            // Vista
                                case "Master Mute":     // XP

                                    if (GetDetails(hMixer, LINE, MIXER[i], out DETAILS))
                                    {
                                        if (DETAILS.paDetails == IntPtr.Zero)
                                            break;

                                        haveMute = true;
                                        bMute = (Marshal.ReadInt32(DETAILS.paDetails) == 0) ? false : true;
                                    }
                                    break;

                                default:
                                    break;
                            }
                        }
                    }
                    #endregion

                    #region Update
                    tb_D_List[index].Tag = value;
                    cb_D_List[index].Tag = value;
                    lb_D_List[index].Tag = value;

                    tb_D_List[index].Enabled = true;
                    cb_D_List[index].Enabled = true;
                    lb_D_List[index].Enabled = true;

                    tb_D_List[index].Minimum = 0;
                    tb_D_List[index].Maximum = 65535;

                    if (haveVol)
                        tb_D_List[index].Value = pfLevel;
                    if (haveMute)
                        cb_D_List[index].Checked = bMute;

                    lb_D_List[index].Text = LINE.tTarget.szPname;

                    tb_D_List[index].ValueChanged += dValueChanged;
                    cb_D_List[index].CheckedChanged += dCheck;

                    Taken_D.Add(index);
                    #endregion
                }

                //
                // end
                //
            }
        }

        // Convert MIXERLINE To MIXERLINECONTROLS
        bool GetControl(IntPtr hMixer,
            XP.Structs.MIXERLINE LINE,
            out XP.Structs.MIXERLINECONTROLS CONTROL)
        {
            try
            {
                XP.Structs.MIXERLINECONTROLS mlc = new XP.Structs.MIXERLINECONTROLS()
                {
                    dwLineID = (uint)LINE.dwLineID,
                    cControls = (uint)LINE.cControls,
                    cbStruct = (uint)Marshal.SizeOf(typeof(XP.Structs.MIXERLINECONTROLS)),
                    pamxctrl = Marshal.AllocHGlobal((int)(Marshal.SizeOf(typeof(XP.Structs.MIXERCONTROL)) * LINE.cControls)),
                    cbmxctrl = (uint)Marshal.SizeOf(typeof(XP.Structs.MIXERCONTROL)),

                };

                if (XP.Api.mixerGetLineControls(hMixer, ref mlc, XP.Enums.lineControlsFlags.MIXER_GETLINECONTROLSF_ALL) == 0)
                {
                    CONTROL = mlc;

                    return true;
                }
            }
            catch { }

            CONTROL = new XP.Structs.MIXERLINECONTROLS();
            return false;
        }

        // Convert MIXERLINECONTROLS To MIXERCONTROL[]
        bool GetMixer(
            IntPtr hMixer,
            XP.Structs.MIXERLINECONTROLS CONTROL,
            out XP.Structs.MIXERCONTROL[] MIXER)
        {
            try
            {
                if (CONTROL.cControls > 0)
                {
                    MIXER = new XP.Structs.MIXERCONTROL[CONTROL.cControls];
                    for (int i = 0; i < CONTROL.cControls; i++)
                    {
                        MIXER[i] = (XP.Structs.MIXERCONTROL)Marshal.PtrToStructure(
                            (IntPtr)((long)CONTROL.pamxctrl + (Marshal.SizeOf(typeof(XP.Structs.MIXERCONTROL)) * i)),
                            typeof(XP.Structs.MIXERCONTROL));
                    }
                    return true;
                }
            }
            catch { MIXER = null; }

            MIXER = null;
            return false;
        }

        // Convert MIXERCONTROL To MIXERCONTROLDETAILS
        bool GetDetails(
            IntPtr hMixer,
            XP.Structs.MIXERLINE LINE,
            XP.Structs.MIXERCONTROL MIXER,
            out XP.Structs.MIXERCONTROLDETAILS DETAILS)
        {
            try
            {
                int Channels;
                {
                    // MIXERCONTROLDETAILS structure
                    // cChannels :: Number of channels on which to get or set control properties. The following values are defined: { .... }
                    // http://msdn.microsoft.com/en-us/library/windows/desktop/dd757294(v=vs.85).aspx

                    if (MIXER.dwControlType == XP.Enums.CONTROLTYPE.MIXERCONTROL_CONTROLTYPE_CUSTOM)
                        Channels = 0;
                    else if (MIXER.fdwControl == XP.Enums.CONTROLF.MIXERCONTROL_CONTROLF_UNIFORM)
                        Channels = 1;
                    else
                        Channels = LINE.cChannels;
                }

                if (Channels == 0)
                    throw new Exception();

                XP.Structs.MIXERCONTROLDETAILS mxcd = new XP.Structs.MIXERCONTROLDETAILS()
                {
                    cbStruct = Marshal.SizeOf(typeof(XP.Structs.MIXERCONTROLDETAILS)),
                    dwControlID = MIXER.dwControlID,
                    cChannels = Channels,
                    paDetails = Marshal.AllocHGlobal(4 * Channels),    // size of int == 4
                    cbDetails = 4 * Channels,                          // size of int == 4
                    item = 0,
                };
                if (XP.Api.mixerGetControlDetails(hMixer, ref mxcd, XP.Enums.ControlDetailsFlags.MIXER_OBJECTF_HMIXER | XP.Enums.ControlDetailsFlags.MIXER_GETCONTROLDETAILSF_VALUE) == 0)
                {
                    DETAILS = mxcd;
                    return true;
                }
            }
            catch (Exception)
            {
            }

            DETAILS = new XP.Structs.MIXERCONTROLDETAILS();
            return false;
        }

        // Set new MIXERCONTROLDETAILS
        bool SetDetails(
            int Left, int Right, // case of [Mute] use (0 / 1 for both) ||  case of [1 channel] the bigger will be taken
            IntPtr hMixer,
            XP.Structs.MIXERLINE LINE,
            XP.Structs.MIXERCONTROL MIXER, // we have 2 option for this -[0]=VOLUME,[1]=MUTE- [look at GetMixer]
            out XP.Structs.MIXERCONTROLDETAILS DETAILS)
        {
            try
            {
                XP.Structs.MIXERCONTROLDETAILS mxcd;
                if (GetDetails(hMixer, LINE, MIXER, out mxcd))
                {
                    int Channels;
                    {
                        // MIXERCONTROLDETAILS structure
                        // cChannels :: Number of channels on which to get or set control properties. The following values are defined: { .... }
                        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd757294(v=vs.85).aspx

                        if (MIXER.dwControlType == XP.Enums.CONTROLTYPE.MIXERCONTROL_CONTROLTYPE_CUSTOM)
                            Channels = 0;
                        else if (MIXER.fdwControl == XP.Enums.CONTROLF.MIXERCONTROL_CONTROLF_UNIFORM)
                            Channels = 1;
                        else
                            Channels = LINE.cChannels;
                    }

                    int[] data = new int[Channels];
                    if (Channels > 1)
                    {
                        data[0] = Left;
                        data[1] = Right;
                    }
                    else
                    {
                        data[0] = (Left > Right) ? Left : Right;
                    }

                    mxcd.cbDetails = 4 * Channels;                         // size of int == 4
                    mxcd.paDetails = Marshal.AllocHGlobal(4 * Channels);   // size of int == 4
                    Marshal.Copy(data, 0, mxcd.paDetails, Channels);
                }

                if (XP.Api.mixerSetControlDetails(hMixer, ref mxcd, XP.Enums.ControlDetailsFlags.MIXER_OBJECTF_HMIXER | XP.Enums.ControlDetailsFlags.MIXER_SETCONTROLDETAILSF_VALUE) == 0 &&
                    GetDetails(hMixer, LINE, MIXER, out mxcd))
                {
                    DETAILS = mxcd;
                    return true;
                }
            }
            catch (Exception)
            {
            }

            DETAILS = new XP.Structs.MIXERCONTROLDETAILS();
            return false;
        }
        #endregion
        #region XP :: Notification
        // capture Mixer events
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case 0x3D0: /*MM_MIXM_LINE_CHANGE*/
                case 0x3D1: /*MM_MIXM_CONTROL_CHANGE*/
                    ThreadPool.QueueUserWorkItem(HandleMassege, m);
                    break;

                default:
                    break;

            }
            base.WndProc(ref m);
        }

        // handle Messeges
        void HandleMassege(object m)
        {
            switch (((Message)m).Msg)
            {
                /*MM_MIXM_LINE_CHANGE*/
                // http://msdn.microsoft.com/en-us/library/dd757367(v=VS.85).aspx
                case 0x3D0:
                    
                    {
                        // Handle to the mixer device (HMIXER) that sent the notification message.
                        IntPtr hMixer = ((Message)m).WParam;

                        // Line identifier for the audio line that has changed state.
                        // This identifier is the same as thedwLineID member of theMIXERLINEstructure returned by themixerGetLineInfofunction.
                        int dwLineID = (int)((Message)m).LParam;

                        // Blat ...
                        XP.Structs.MIXERLINE LINE;
                        XP.Structs.MIXERCONTROL[] MIXER;
                        XP.Structs.MIXERCONTROLDETAILS[] DETAILS;

                        if (GetMixerLine(hMixer, dwLineID, out LINE, out MIXER, out DETAILS))
                        {
                            for (int index = 0; index < DETAILS.Length; index++)
                            {
                                var item = DETAILS[index];

                                // start
                                int[] result = new int[item.cChannels];
                                for (int i = 0; i < item.cChannels; i++)
                                {
                                    result[i] = Marshal.ReadInt32((IntPtr)((long)item.paDetails + (i * 4)));
                                }
                                base.Invoke(wtfHandler, LINE, MIXER[index], DETAILS[index], result);
                                // end
                            }
                        }
                    }
                    break;

                
                /*MM_MIXM_CONTROL_CHANGE*/
                // http://msdn.microsoft.com/en-us/library/dd757368(v=VS.85).aspx
                case 0x3D1:    
                    {
                        // Handle to the mixer device (HMIXER) that sent the notification message.
                        IntPtr hMixer = ((Message)m).WParam;

                        // Control identifier for the mixer control that has changed state.
                        // This identifier is the same as thedwControlID member of theMIXERCONTROLstructure returned by themixerGetLineControlsfunction.
                        int dwControlID = (int)((Message)m).LParam;

                        // Blat ...
                        XP.Structs.MIXERLINE LINE;
                        XP.Structs.MIXERCONTROL MIXER;
                        XP.Structs.MIXERCONTROLDETAILS DETAILS;

                        if (GetMixerLine(hMixer, dwControlID, out LINE, out MIXER, out DETAILS))
                        {
                            // start
                            int[] result = new int[DETAILS.cChannels];
                            for (int i = 0; i < DETAILS.cChannels; i++)
                            {
                                result[i] = Marshal.ReadInt32((IntPtr)((long)DETAILS.paDetails + (i * 4)));
                            }
                            base.Invoke(wtfHandler, LINE, MIXER, DETAILS, result);
                            // end
                        }
                    }
                    break;
            }
        }

        // get MIXERLINE from specific Handle & LineId
        bool GetMixerLine(
            IntPtr hMixer, int dwLineID,
            out XP.Structs.MIXERLINE LINE,
            out XP.Structs.MIXERCONTROL[] MIXER,
            out XP.Structs.MIXERCONTROLDETAILS[] DETAILS)
        {
            try
            {
                // Blat ...
                foreach (var item in deviceMixer[hMixer])
                {
                    if (item.dwLineID == dwLineID)
                    {
                        XP.Structs.MIXERLINE _LINE = item;
                        XP.Structs.MIXERLINECONTROLS _CONTROL;
                        XP.Structs.MIXERCONTROL[] _MIXER;

                        if (GetControl(hMixer, _LINE, out _CONTROL) &&
                            GetMixer(hMixer, _CONTROL, out _MIXER))
                        {
                            LINE = _LINE;
                            MIXER = _MIXER;
                            DETAILS = new XP.Structs.MIXERCONTROLDETAILS[_MIXER.Length];
                            for (int i = 0; i < _MIXER.Length; i++)
                            {
                                GetDetails(hMixer, LINE, _MIXER[i], out DETAILS[i]);
                            }

                            return true;
                        }
                    }
                }
            }
            catch (Exception)
            {
                //Console.WriteLine();
            }

            LINE = new XP.Structs.MIXERLINE();
            MIXER = new XP.Structs.MIXERCONTROL[0];
            DETAILS = new XP.Structs.MIXERCONTROLDETAILS[0];
            return false;    
        }

        // get MIXERLINE from specific Handle & ControlId
        bool GetMixerLine(
            IntPtr hMixer, int dwControlID,
            out XP.Structs.MIXERLINE LINE,
            out XP.Structs.MIXERCONTROL MIXER,
            out XP.Structs.MIXERCONTROLDETAILS DETAILS)
        {
            try
            {
                foreach (var item in deviceMixer[hMixer])
                {
                    XP.Structs.MIXERLINECONTROLS _CONTROL;
                    XP.Structs.MIXERCONTROL[] _MIXER;
                    XP.Structs.MIXERCONTROLDETAILS _DETAILS;

                    if (GetControl(hMixer, item, out _CONTROL) &&
                        GetMixer(hMixer, _CONTROL, out _MIXER))
                    {
                        for (int i = 0; i < _MIXER.Length; i++)
                        {
                            if (_MIXER[i].dwControlID == dwControlID)
                            {
                                if (GetDetails(hMixer, item, _MIXER[i], out _DETAILS))
                                {
                                    // done
                                    LINE = item;
                                    MIXER = _MIXER[i];
                                    DETAILS = _DETAILS;
                                    return true;
                                }
                                else
                                {
                                    LINE = new XP.Structs.MIXERLINE();
                                    MIXER = new XP.Structs.MIXERCONTROL();
                                    DETAILS = new XP.Structs.MIXERCONTROLDETAILS();
                                    return false;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                //Console.WriteLine();
            }

            LINE = new XP.Structs.MIXERLINE();
            MIXER = new XP.Structs.MIXERCONTROL();
            DETAILS = new XP.Structs.MIXERCONTROLDETAILS();
            return false;
        }

        // base.Invoke Handler
        void HandleInvoke(
            XP.Structs.MIXERLINE LINE,
            XP.Structs.MIXERCONTROL MIXER,
            XP.Structs.MIXERCONTROLDETAILS DETAILS,
            int[] result)
        {
            switch (MIXER.szShortName)
            {
                case "Mute":            // Vista
                case "Master Mute":     // XP
                    {
                        foreach (var ctrl in cb_D_List)
                        {
                            if (ctrl.Tag == null)
                                continue;

                            XP.Structs.MIXERLINE SOURCE = (XP.Structs.MIXERLINE)ctrl.Tag;
                            XP.Structs.MIXERLINE TARGET = LINE;

                            if (SOURCE.szShortName == TARGET.szShortName &&
                                SOURCE.tTarget.szPname == TARGET.tTarget.szPname &&
                                SOURCE.dwComponentType == TARGET.dwComponentType)
                            {
                                lock (dObject)
                                {
                                    dLock = true;

                                    try
                                    {
                                        if (DETAILS.paDetails != IntPtr.Zero)
                                        {
                                            ctrl.Checked = (Marshal.ReadInt32(DETAILS.paDetails) == 0) ? false : true;

                                            changeBox.AppendText(string.Format("Device :: {0}\n", LINE.tTarget.szPname));
                                            changeBox.AppendText(string.Format("Mute :: {0}\n", ctrl.Checked));
                                            changeBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                        }
                                        else
                                        {
                                            changeBox.AppendText(string.Format("Device :: {0}\n", LINE.tTarget.szPname));
                                            changeBox.AppendText(string.Format("Mute :: {0}\n", "NO_DATA"));
                                            changeBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                        }
                                    }
                                    catch (Exception)
                                    {
                                        //throw;
                                    }

                                    dLock = false; 
                                }
                                break;
                            }
                        }
                    }
                    break;

                case "Volume":          // Vista
                case "Master Volume":   // XP
                    {
                        foreach (var ctrl in tb_D_List)
                        {
                            if (ctrl.Tag == null)
                                continue;

                            XP.Structs.MIXERLINE SOURCE = (XP.Structs.MIXERLINE)ctrl.Tag;
                            XP.Structs.MIXERLINE TARGET = LINE;

                            if (SOURCE.szShortName == TARGET.szShortName &&
                                SOURCE.tTarget.szPname == TARGET.tTarget.szPname &&
                                SOURCE.dwComponentType == TARGET.dwComponentType)
                            {
                                lock (dObject)
                                {
                                    dLock = true;

                                    try
                                    {
                                        if (DETAILS.paDetails != IntPtr.Zero)
                                        {
                                            // because we have 2 sides
                                            // we have to find the bigger one,
                                            // he hold the real volume.

                                            int pfLevel = 0;
                                            for (int blat = 0; blat < DETAILS.cChannels; blat++)
                                            {
                                                int vol = Marshal.ReadInt32((IntPtr)((long)DETAILS.paDetails + (blat * 4)));
                                                if (pfLevel < vol) pfLevel = vol;
                                            }
                                            ctrl.Value = pfLevel;

                                            changeBox.AppendText(string.Format("Device :: {0}\n", LINE.tTarget.szPname));
                                            changeBox.AppendText(string.Format("Volume :: {0}\n", pfLevel));
                                            changeBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                        }
                                        else
                                        {
                                            changeBox.AppendText(string.Format("Device :: {0}\n", LINE.tTarget.szPname));
                                            changeBox.AppendText(string.Format("Volume :: {0}\n", "NO_DATA"));
                                            changeBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                        }
                                    }
                                    catch (Exception)
                                    {
                                        //throw;
                                    }

                                    dLock = false; 
                                }
                                break;
                            }
                        }
                    }
                    break;
            }
        }
        #endregion

        #region VISTA :: Properties
        volatile int Counter = 0;
        volatile bool Worker = false;
        volatile bool CaptureLast = true;
        volatile object WorkerLock = new object();
        volatile Dictionary<int, object> existBlock = new Dictionary<int, object>();
        volatile Dictionary<int, bool> existCheck = new Dictionary<int, bool>();
        volatile Dictionary<int, List<Vista.IAudioSessionControl>> sessionCheck =
            new Dictionary<int, List<Vista.IAudioSessionControl>>();

        volatile List<int> pIdlist = new List<int>();
        volatile List<Vista.IAudioSessionControl> sessionList = new List<Vista.IAudioSessionControl>();
        volatile List<Vista.IAudioEndpointVolume> volumeList = new List<Vista.IAudioEndpointVolume>();
        volatile Dictionary<Vista.IAudioSessionEvents, Vista.IAudioSessionControl> SessionManager =
            new Dictionary<Vista.IAudioSessionEvents, Vista.IAudioSessionControl>();
        volatile Dictionary<Vista.IMMDevice, Vista.IAudioEndpointVolume> DeviceManager =
            new Dictionary<Vista.IMMDevice, Vista.IAudioEndpointVolume>();
        #endregion
        #region VISTA :: Function
        /// <summary>
        /// Creates a single uninitialized object of the class associated with a specified CLSID.
        /// </summary>
        [DllImport("ole32.Dll")]
        static extern uint CoCreateInstance(ref Guid rclsid, [MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
            Vista.CLSCTX dwClsContext, ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppv);
        
        /// <summary>
        /// MMDeviceEnumerator
        /// </summary>
        [ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
        public class MMDeviceEnumerator { }

        // Init
        private void Init()
        {
            /*
             * Before enumerating the endpoint devices in the system,
             * the client must first call the Windows CoCreateInstance function to create a device enumerator.
             * A device enumerator is an object with an IMMDeviceEnumerator interface.
             * For information about CoCreateInstance, see the Windows SDK documentation.
             */

            Vista.IMMDeviceEnumerator enumrator = null;

            {
                // COM Interop Tutorials :: PART 1 :: Creating a COM Class Wrapper { Declaring a COM coclass }
                // http://msdn.microsoft.com/en-us/library/aa645736(v=VS.71).aspx

                /*
                    // mmdeviceapi.h
                    
                    #ifdef __cplusplus
                    class DECLSPEC_UUID("BCDE0395-E52F-467C-8E3D-C4579291692E")
                    MMDeviceEnumerator;
                    #endif
                 */

                enumrator = new MMDeviceEnumerator() as Vista.IMMDeviceEnumerator;
            }

            {
                // CoCreateInstance -> Managed Way
                // http://pinvoke.net/default.aspx/ole32/CoCreateInstance.html

                /*
                    Have a look at System.Activator.CreateInstance and its various overloads. Sample:                    
                    Guid CLSID_ShellDesktop = new Guid("00021400-0000-0000-C000-000000000046");
                    Type shellDesktopType = Type.GetTypeFromCLSID(CLSID_ShellDesktop, true);
                    object shellDesktop = Activator.CreateInstance(shellDesktopType);

                 */

                Type type = Type.GetTypeFromCLSID(new Guid("BCDE0395-E52F-467C-8E3D-C4579291692E"), false);
                enumrator = Activator.CreateInstance(type) as Vista.IMMDeviceEnumerator;
            }

            {
                // CoCreateInstance -> Native Way
                // http://msdn.microsoft.com/en-us/library/windows/desktop/ms686615(v=vs.85).aspx

                /*
                    // About MMDevice API
                    // http://msdn.microsoft.com/en-us/library/windows/desktop/dd316556(v=VS.85).aspx
                    
                    const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
                    const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
                    hr = CoCreateInstance(
                            CLSID_MMDeviceEnumerator, NULL,
                            CLSCTX_ALL, IID_IMMDeviceEnumerator,
                            (void**)&pEnumerator);
                 */

                object rReturnedComObject;
                Guid MMDeviceEnumerator = new Guid("BCDE0395-E52F-467C-8E3D-C4579291692E");
                Guid IMMDeviceEnumerator = new Guid("A95664D2-9614-4F35-A746-DE8DB63617E6");
                CoCreateInstance(ref MMDeviceEnumerator, null, Vista.CLSCTX.CLSCTX_ALL, ref IMMDeviceEnumerator, out rReturnedComObject);
                enumrator = (Vista.IMMDeviceEnumerator)rReturnedComObject;
            }

            //
            // Register to <IMMDeviceEnumerator :: RegisterEndpointNotificationCallback>
            // happen when Device install / uninstall
            //

            Vista.IMMNotificationClient client = new NotificationClient(enumrator);
            (client as NotificationClient).OnAdd += delegate(Vista.IMMDevice newDevice) { Init(newDevice); };
            (client as NotificationClient).OnRemove += delegate(Vista.IMMDevice oldDevice)
            {
                base.Invoke(
                    (MethodInvoker)delegate
                    {
                        #region Register
                        if (DeviceManager.ContainsKey(oldDevice))
                        {
                            // get the IAudioEndpointVolume
                            Vista.IAudioEndpointVolume iAudioEndpointVolume = DeviceManager[oldDevice];

                            // little job here
                            int index = 0;
                            bool found = false;
                            for (int i = 0; i < tb_D_List.Count; i++)
                            {
                                if (tb_D_List[i].Tag != null)
                                {
                                    if (tb_D_List[i].Tag == iAudioEndpointVolume)
                                    {
                                        index = i;
                                        found = true;
                                        break;
                                    }
                                }

                            }

                            try
                            {
                                if (found)
                                {
                                    tb_D_List[index].ValueChanged -= dValueChanged;
                                    cb_D_List[index].CheckedChanged -= dCheck;

                                    tb_D_List[index].Value = 0;
                                    cb_D_List[index].Checked = false;

                                    tb_D_List[index].Enabled = false;
                                    cb_D_List[index].Enabled = false;

                                    tb_D_List[index].Tag = null;
                                    cb_D_List[index].Tag = null;
                                }
                            }
                            catch { }
                            finally
                            {
                                if (found) { Taken_D.Remove(index); }
                                volumeList.Remove(iAudioEndpointVolume);
                                DeviceManager.Remove(oldDevice);
                            }
                        }
                        #endregion
                    });
            };
            enumrator.RegisterEndpointNotificationCallback(client);

            /*
             * The client calls the IMMDeviceEnumerator::EnumAudioEndpoints method to create a collection of endpoint objects.
             * Each endpoint object represents an audio endpoint device in the system.
             * In this call, the client specifies whether the collection should contain all of the rendering devices in the system,
             * all of the capture devices, or both.
             */

            Vista.IMMDeviceCollection collection;
            int result = enumrator.EnumAudioEndpoints(Vista.EDataFlow.eAll, Vista.EDeviceState.DEVICE_STATE_ACTIVE, out collection);
            if (result != 0)
                return;

            /*
             * get result from the collection
             */

            uint pDevices = 0;
            collection.GetCount(out pDevices);

            for (int i = 0; i < pDevices; i++)
            {
                //
                // get IMMDevice
                //

                Vista.IMMDevice IMMDevice;
                collection.Item((uint)i, out IMMDevice);
                Init(IMMDevice);
            }
        }
        private void Init(Vista.IMMDevice device)
        {
            //
            // get IAudioSessionManager 
            //

            {
                object IAudioSessionManager;
                Vista.IAudioSessionEnumerator iAudioSessionEnumerator;
                Guid guid = typeof(Vista.IAudioSessionManager2).GUID;
                device.Activate(ref guid, Vista.CLSCTX.CLSCTX_ALL, IntPtr.Zero, out IAudioSessionManager);
                (IAudioSessionManager as Vista.IAudioSessionManager2).GetSessionEnumerator(out iAudioSessionEnumerator);

                //
                // Register to <IAudioSessionManager :: RegisterSessionNotification>
                // happen when new incoming session Come [like 100Player, Winamp, ...]
                //

                Vista.IAudioSessionNotification iAudioSessionNotification = new iAudioSessionNotification();
                (iAudioSessionNotification as iAudioSessionNotification).AcceptSesson +=
                    delegate(Vista.IAudioSessionControl sessionControl)
                    {
                        #region AcceptSession
                        base.Invoke(
                            (MethodInvoker)delegate
                                {
                                    UInt32 pID;
                                    (sessionControl as Vista.IAudioSessionControl2).GetProcessId(out pID);

                                    string sID;
                                    (sessionControl as Vista.IAudioSessionControl2).GetSessionInstanceIdentifier(out sID);

                                    Vista.AudioSessionState NewState;
                                    (sessionControl as Vista.IAudioSessionControl2).GetState(out NewState);

                                    logBox.AppendText(string.Format("Session [Check :: New]\n"));
                                    logBox.AppendText(string.Format("State :: {0}\n", NewState));
                                    logBox.AppendText(string.Format("sID :: {0}\n", sID));
                                    logBox.AppendText(string.Format("PID :: {0}\n", pID));
                                    logBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                });

                        if (CaptureLast)
                            GetLastSession(sessionControl);
                        else
                            Init(sessionControl);
                        
                        return 1; 
                        #endregion
                    };
                (IAudioSessionManager as Vista.IAudioSessionManager2).RegisterSessionNotification(iAudioSessionNotification);

                // get Count
                int sCount;
                iAudioSessionEnumerator.GetCount(out sCount);

                // enum all Session
                for (int sIndex = 0; sIndex < sCount; sIndex++)
                {
                    // get iAudioSessionControl
                    Vista.IAudioSessionControl iAudioSessionControl;
                    iAudioSessionEnumerator.GetSession(0, out iAudioSessionControl);

                    base.Invoke(
                        (MethodInvoker)delegate
                        {
                            UInt32 pID;
                            (iAudioSessionControl as Vista.IAudioSessionControl2).GetProcessId(out pID);

                            string sID;
                            (iAudioSessionControl as Vista.IAudioSessionControl2).GetSessionInstanceIdentifier(out sID);

                            Vista.AudioSessionState NewState;
                            (iAudioSessionControl as Vista.IAudioSessionControl2).GetState(out NewState);

                            logBox.AppendText(string.Format("Session [Check :: Exist]\n"));
                            logBox.AppendText(string.Format("State :: {0}\n", NewState));
                            logBox.AppendText(string.Format("sID :: {0}\n", sID));
                            logBox.AppendText(string.Format("pID :: {0}\n", pID));
                            logBox.AppendText(string.Format("---- ---- ---- ----\n"));
                        });

                    if (CaptureLast)
                        GetLastSession(iAudioSessionControl);
                    else
                        Init(iAudioSessionControl);
                }
            }

            //
            // get IAudioEndpointVolume
            //

            {
                object IAudioEndpointVolume;
                Guid guid = typeof(Vista.IAudioEndpointVolume).GUID;
                device.Activate(ref guid, Vista.CLSCTX.CLSCTX_ALL, IntPtr.Zero, out IAudioEndpointVolume);
                volumeList.Add(IAudioEndpointVolume as Vista.IAudioEndpointVolume);
                DeviceManager.Add(device, IAudioEndpointVolume as Vista.IAudioEndpointVolume);

                //
                // Register to <IAudioEndpointVolume :: RegisterControlChangeNotify>
                // happen when device Change somthing [Volume, Mute, ...]
                //

                var callabck = new AudioEndpointVolumeCallback(IAudioEndpointVolume as Vista.IAudioEndpointVolume, device);
                callabck.VolumeChanged += (Suca, Blat) =>
                {
                    base.Invoke(
                        (MethodInvoker)delegate
                        {
                            #region VolumeChanged
                            try
                            {
                                int index = 0;
                                bool found = false;
                                for (int i = 0; i < tb_D_List.Count; i++)
                                {
                                    if (tb_D_List[i].Tag != null)
                                    {
                                        if (tb_D_List[i].Tag == Blat.iAudioEndpointVolume)
                                        {
                                            index = i;
                                            found = true;
                                            break;
                                        }
                                    }

                                }

                                if (found)
                                {
                                    lock (dObject)
                                    {
                                        dLock = true;

                                        tb_D_List[index].Value = (int)(Blat.fMasterVolume * 100f);
                                        cb_D_List[index].Checked = Blat.bMuted;

                                        changeBox.AppendText(string.Format("Device :: {0}\n", GetName(Blat.device)));
                                        changeBox.AppendText(string.Format("Volume :: {0}\n", Blat.fMasterVolume * 100f));
                                        changeBox.AppendText(string.Format("Mute :: {0}\n", Blat.bMuted));
                                        changeBox.AppendText(string.Format("---- ---- ---- ----\n"));

                                        dLock = false;
                                    }
                                }
                            }
                            catch (Exception)
                            {
                                //throw;
                            }
                            #endregion
                        });
                };
                (IAudioEndpointVolume as Vista.IAudioEndpointVolume).RegisterControlChangeNotify(callabck);

                //
                // update settings
                //

                base.Invoke(
                    (MethodInvoker)delegate
                    {
                        #region update settings
                        try
                        {
                            int index = 0;
                            bool found = false;
                            for (index = 0; index < tb_D_List.Count; index++)
                            {
                                if (!Taken_D.Contains(index) &&
                                    tb_D_List[index].Enabled == false)
                                {
                                    found = true;
                                    break;
                                }
                            }

                            if (found)
                            {
                                bool bMute;
                                float pfLevel = 0;
                                ((IAudioEndpointVolume as Vista.IAudioEndpointVolume)).GetMasterVolumeLevelScalar(out pfLevel);
                                ((IAudioEndpointVolume as Vista.IAudioEndpointVolume)).GetMute(out bMute);

                                tb_D_List[index].Tag = IAudioEndpointVolume;
                                cb_D_List[index].Tag = IAudioEndpointVolume;
                                lb_D_List[index].Tag = IAudioEndpointVolume;

                                tb_D_List[index].Enabled = true;
                                cb_D_List[index].Enabled = true;
                                lb_D_List[index].Enabled = true;

                                tb_D_List[index].Value = (int)(pfLevel * 100f);
                                cb_D_List[index].Checked = bMute;
                                lb_D_List[index].Text = GetName(device);

                                try
                                {
                                    logBox.AppendText(string.Format("Device [Add] :: {0}\n", GetName(device)));
                                    logBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                }
                                catch (Exception)
                                {
                                    //throw;
                                }

                                tb_D_List[index].ValueChanged += dValueChanged;
                                cb_D_List[index].CheckedChanged += dCheck;

                                Taken_D.Add(index);
                            }
                        }
                        catch (Exception)
                        {
                            //throw;
                        }
                        #endregion
                    }
                );
            }
        }
        private void Init(object _session)
        {
            Vista.IAudioSessionControl session = _session as Vista.IAudioSessionControl;

            //
            // do little check
            //
            
            UInt32 pID;
            lock (PidCheck)
            {
                (session as Vista.IAudioSessionControl2).GetProcessId(out pID);

                if ( pID <= 0
                    || pIdlist.Contains((int)pID) )
                    return;


                try
                {
                    Thread.Sleep(250);
                    var CheckExist = Process.GetProcessById((int)pID).MainModule.FileName;

                    base.Invoke(
                        (MethodInvoker)delegate { pIdlist.Add((int)pID); });
                }
                catch (Exception)
                {
                    return;
                    //throw;
                }
            }

            //
            // Register to <IAudioSessionControl :: RegisterAudioSessionNotification>
            // happen when Session end / pause / start / stop
            // (session = new program. like winamp, 100FM player, ...)
            //

            iAudioSessionEvents AudioSessionEvents;

            {
                AudioSessionEvents = new iAudioSessionEvents();
                AudioSessionEvents.StateChanged += delegate(Vista.IAudioSessionEvents sessionEvent, Vista.AudioSessionState NewState)
                {
                    #region State Changed
                    // IAudioSessionEvents Check
                    if (SessionManager.ContainsKey(sessionEvent) == false) { return 1; }

                    // get Index
                    int index = 0;
                    bool found = false;
                    for (index = 0; index < tb_S_List.Count; index++)
                    {
                        if (tb_S_List[index].Tag == SessionManager[sessionEvent])
                        {
                            found = true;
                            break;
                        }
                    }

                    // get Pid
                    uint processId;
                    (SessionManager[sessionEvent] as Vista.IAudioSessionControl2).GetProcessId(out processId);

                    // get Sid
                    string sID;
                    (SessionManager[sessionEvent] as Vista.IAudioSessionControl2).GetSessionInstanceIdentifier(out sID);

                    // Pid Check
                    try { var CheckExist = Process.GetProcessById((int)processId).MainModule.FileName; }
                    catch { NewState = Vista.AudioSessionState.AudioSessionStateExpired; }

                    // Update Log
                    base.Invoke(
                        (MethodInvoker)delegate
                    {
                        changeBox.AppendText(string.Format("Session :: {0}\n", found ? lb_S_List[index].Text : "NULL"));
                        changeBox.AppendText(string.Format("State :: {0}\n", NewState));
                        changeBox.AppendText(string.Format("sID :: {0}\n", sID));
                        changeBox.AppendText(string.Format("pID :: {0}\n", processId));
                        changeBox.AppendText(string.Format("---- ---- ---- ----\n"));
                    });

                    // [[ AudioSessionStateExpired ]]
                    if (NewState == Vista.AudioSessionState.AudioSessionStateExpired)
                    {
                        #region Remove
                        base.Invoke(
                            (MethodInvoker)delegate
                            {
                                try
                                {
                                    if (found)
                                    {
                                        int idx = index;
                                        lock (tb_S_List[idx])
                                        {
                                            if (tb_S_List[index].Enabled == false)
                                                return;

                                            tb_S_List[index].Tag = null;
                                            cb_S_List[index].Tag = null;
                                            lb_S_List[index].Tag = null;

                                            tb_S_List[index].ValueChanged -= sValueChanged;
                                            cb_S_List[index].CheckedChanged -= sCheck;

                                            tb_S_List[index].Value = 0;
                                            cb_S_List[index].Checked = false;
                                            lb_S_List[index].Text = null;

                                            tb_S_List[index].Enabled = false;
                                            cb_S_List[index].Enabled = false;
                                            lb_S_List[index].Enabled = false;

                                            logBox.AppendText(string.Format("Event :: Init ^ StateChanged { AudioSessionStateExpired } \n"));
                                            logBox.AppendText(string.Format("Session [Remove] :: {0}\n", lb_S_List[index].Text));
                                            logBox.AppendText(string.Format("State :: {0}\n", NewState));
                                            logBox.AppendText(string.Format("sID :: {0}\n", sID));
                                            logBox.AppendText(string.Format("pID :: {0}\n", processId));
                                            logBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                        }
                                    }
                                }
                                catch (Exception) { }
                                finally
                                {
                                    if (found) { Taken_S.Remove(index); }
                                    pIdlist.Remove((int)processId);
                                    if (SessionManager.ContainsKey(sessionEvent))
                                    {
                                        sessionList.Remove(SessionManager[sessionEvent]);
                                        SessionManager.Remove(sessionEvent);
                                    }
                                }
                            }); 
                        #endregion
                    }
                    
                    // Done
                    return 1;
                    #endregion
                };
                AudioSessionEvents.VolumeChanged += delegate(Vista.IAudioSessionEvents sessionEvent, float pfLevel, bool bMute)
                {
                    #region Volume Changed
                    // IAudioSessionEvents Check
                    if (SessionManager.ContainsKey(sessionEvent) == false) { return 1; }

                    // get Index
                    int index = 0;
                    bool found = false;
                    for (index = 0; index < tb_S_List.Count; index++)
                    {
                        if (tb_S_List[index].Tag == SessionManager[sessionEvent])
                        {
                            found = true;
                            break;
                        }
                    }

                    // Update
                    if (found)
                    {
                        {
                            #region [[ Update ]]
                            base.Invoke(
                                (MethodInvoker)delegate
                                {
                                    sLock = true;

                                    try
                                    {
                                        lock (sObject)
                                        {
                                            uint processId;
                                            (SessionManager[sessionEvent] as Vista.IAudioSessionControl2).GetProcessId(out processId);

                                            string sID;
                                            (session as Vista.IAudioSessionControl2).GetSessionInstanceIdentifier(out sID);

                                            Vista.AudioSessionState NewState;
                                            (session as Vista.IAudioSessionControl2).GetState(out NewState);

                                            tb_S_List[index].Value = (int)(pfLevel * 100f);
                                            cb_S_List[index].Checked = bMute;

                                            changeBox.AppendText(string.Format("Session :: {0}\n",
                                                string.IsNullOrEmpty(Process.GetProcessById((int)processId).MainWindowTitle) ?
                                                    FileVersionInfo.GetVersionInfo(Process.GetProcessById((int)processId).MainModule.FileName).FileDescription :
                                                    Process.GetProcessById((int)processId).MainWindowTitle));
                                            changeBox.AppendText(string.Format("State :: {0}\n", NewState));
                                            changeBox.AppendText(string.Format("sID :: {0}\n", sID));
                                            changeBox.AppendText(string.Format("pID :: {0}\n", processId));
                                            changeBox.AppendText(string.Format("---- Info ----\n"));
                                            changeBox.AppendText(string.Format("Volume :: {0}\n", pfLevel * 100f));
                                            changeBox.AppendText(string.Format("Mute :: {0}\n", bMute));
                                            changeBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                            //session
                                        }

                                    }
                                    catch (Exception)
                                    {
                                        //throw;
                                    }

                                    sLock = false;
                                }
                            );
                            #endregion
                        }

                        {
                            #region [[ Fat Man ]]
                            Vista.AudioSessionState state;
                            session.GetState(out state);
                            if (state == Vista.AudioSessionState.AudioSessionStateExpired ||
                                state == Vista.AudioSessionState.AudioSessionStateInactive)
                            {
                                //
                                // bug Fix
                                // wmp close & change volume event loaded !
                                //

                                // check if such key exist
                                if (existCheck.ContainsKey((int)pID) == false)
                                {
                                    existCheck.Add((int)pID, false);
                                    existBlock.Add((int)pID, new object());
                                }

                                // if thread not work >> start it [like timer with parameters]
                                if (existCheck[(int)pID] == false)
                                {
                                    uint procSescs;
                                    (SessionManager[sessionEvent] as Vista.IAudioSessionControl2).GetProcessId(out procSescs);

                                    var ses = session;
                                    var proc = procSescs;
                                    var idx = index;
                                    var sess = sessionEvent;

                                    string sID;
                                    (ses as Vista.IAudioSessionControl2).GetSessionInstanceIdentifier(out sID);

                                    Vista.AudioSessionState NewState;
                                    (ses as Vista.IAudioSessionControl2).GetState(out NewState);

                                    ThreadPool.QueueUserWorkItem(
                                        delegate(object processID)
                                        {
                                            int processsId = int.Parse(processID.ToString());
                                            try
                                            {
                                                if (existCheck[processsId] == true)
                                                    return;

                                            }
                                            catch (Exception)
                                            {
                                                // can be happen because
                                                // we release it while
                                                // there is some incoming input

                                                return;
                                            }

                                            lock (existBlock[processsId])
                                            {
                                                // lock handle
                                                existCheck[(int)processsId] = true;


                                                try
                                                {
                                                    int Tt = -1;
                                                    do
                                                    {
                                                        Thread.Sleep(500);
                                                        var handle = Process.GetProcessById((int)processsId).Handle;
                                                    } while (++Tt < (20));
                                                }
                                                catch
                                                {
                                                    #region Remove
                                                    base.Invoke(
                                                        (MethodInvoker)delegate
                                                        {
                                                            try
                                                            {
                                                                lock (tb_S_List[idx])
                                                                {
                                                                    if (tb_S_List[idx].Enabled == false)
                                                                        return;

                                                                    tb_S_List[idx].Tag = null;
                                                                    cb_S_List[idx].Tag = null;
                                                                    lb_S_List[idx].Tag = null;

                                                                    tb_S_List[idx].ValueChanged -= sValueChanged;
                                                                    cb_S_List[idx].CheckedChanged -= sCheck;

                                                                    tb_S_List[idx].Value = 0;
                                                                    cb_S_List[idx].Checked = false;
                                                                    lb_S_List[idx].Text = null;

                                                                    tb_S_List[idx].Enabled = false;
                                                                    cb_S_List[idx].Enabled = false;
                                                                    lb_S_List[idx].Enabled = false;

                                                                    logBox.AppendText(string.Format("Event :: Init ^ VolumeChanged\n"));
                                                                    logBox.AppendText(string.Format("Session [Remove] :: {0}\n", lb_S_List[idx].Text));
                                                                    logBox.AppendText(string.Format("State :: {0}\n", NewState));
                                                                    logBox.AppendText(string.Format("sID :: {0}\n", sID));
                                                                    logBox.AppendText(string.Format("pID :: {0}\n", processsId));
                                                                    logBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                                                }
                                                            }
                                                            catch (Exception) { }
                                                            finally
                                                            {
                                                                Taken_S.Remove(idx);
                                                                pIdlist.Remove(processsId);

                                                                if (SessionManager.ContainsKey(sess))
                                                                {
                                                                    sessionList.Remove(SessionManager[sess]);
                                                                    SessionManager.Remove(sess);
                                                                }
                                                            }
                                                        });
                                                    #endregion
                                                }
                                            }

                                            // release handle
                                            existBlock.Remove(processsId);
                                            existCheck.Remove(processsId);

                                        }, pID);
                                }
                            }
                            #endregion
                        }
                    }

                    return 1;
                    #endregion
                };
                session.RegisterAudioSessionNotification(AudioSessionEvents);
            }

            //
            // update settings
            //

            base.Invoke(
                (MethodInvoker)delegate
                {
                    #region update settings
                    try
                    {
                        // Update Session List
                        sessionList.Add(session);
                        SessionManager.Add(AudioSessionEvents, session);

                        // get Index
                        int index = 0;
                        bool found = false;
                        for (index = 0; index < tb_S_List.Count; index++)
                        {
                            if (!Taken_S.Contains(index) &&
                                tb_S_List[index].Enabled == false)
                            {
                                found = true;
                                break;
                            }
                        }

                        if (found)
                        {
                            {
                                #region [[ Add ]]
                                bool bMute;
                                float pfLevel;
                                string sID;
                                Vista.AudioSessionState NewState;
                                (session as Vista.ISimpleAudioVolume).GetMasterVolume(out pfLevel);
                                (session as Vista.ISimpleAudioVolume).GetMute(out bMute);
                                (session as Vista.IAudioSessionControl2).GetSessionInstanceIdentifier(out sID);
                                (session as Vista.IAudioSessionControl2).GetState(out NewState);

                                tb_S_List[index].Tag = session;
                                cb_S_List[index].Tag = session;
                                lb_S_List[index].Tag = session;

                                tb_S_List[index].Enabled = true;
                                cb_S_List[index].Enabled = true;
                                lb_S_List[index].Enabled = true;

                                tb_S_List[index].Value = (int)(pfLevel * 100f);
                                cb_S_List[index].Checked = bMute;
                                lb_S_List[index].Text = string.IsNullOrEmpty(Process.GetProcessById((int)pID).MainWindowTitle) ?
                                    FileVersionInfo.GetVersionInfo(Process.GetProcessById((int)pID).MainModule.FileName).FileDescription : Process.GetProcessById((int)pID).MainWindowTitle;

                                logBox.AppendText(string.Format("Session [Add] :: {0}\n", lb_S_List[index].Text));
                                logBox.AppendText(string.Format("State :: {0}\n", NewState));
                                logBox.AppendText(string.Format("sID :: {0}\n", sID));
                                logBox.AppendText(string.Format("pID :: {0}\n", pID));
                                logBox.AppendText(string.Format("---- ---- ---- ----\n"));

                                tb_S_List[index].ValueChanged += sValueChanged;
                                cb_S_List[index].CheckedChanged += sCheck;

                                Taken_S.Add(index); 
                                #endregion
                            }

                            {
                                #region [[ Little Boy ]]
                                uint processId;
                                (session as Vista.IAudioSessionControl2).GetProcessId(out processId);

                                Vista.AudioSessionState state;
                                session.GetState(out state);
                                if (state == Vista.AudioSessionState.AudioSessionStateExpired ||
                                    state == Vista.AudioSessionState.AudioSessionStateInactive)
                                {
                                    //
                                    // bug Fix
                                    // wmp close & start new session !
                                    //

                                    var ses = session;
                                    var proc = processId;
                                    var idx = index;

                                    ThreadPool.QueueUserWorkItem(
                                        delegate(object processID)
                                        {
                                            int processsId = int.Parse(processID.ToString());

                                            try
                                            {
                                                int Tt = -1;
                                                while (++Tt < 20)
                                                {
                                                    Thread.Sleep(500);
                                                    var CheckExist = Process.GetProcessById((int)processsId).Handle;
                                                }
                                                Console.WriteLine();
                                            }
                                            catch
                                            {
                                                #region Remove
                                                base.Invoke(
                                                    (MethodInvoker)delegate
                                                    {
                                                        try
                                                        {
                                                            lock (tb_S_List[idx])
                                                            {
                                                                if (tb_S_List[idx].Enabled == false)
                                                                    return;

                                                                string sID;
                                                                (ses as Vista.IAudioSessionControl2).GetSessionInstanceIdentifier(out sID);

                                                                Vista.AudioSessionState NewState;
                                                                (ses as Vista.IAudioSessionControl2).GetState(out NewState);

                                                                tb_S_List[idx].Tag = null;
                                                                cb_S_List[idx].Tag = null;
                                                                lb_S_List[idx].Tag = null;

                                                                tb_S_List[idx].ValueChanged -= sValueChanged;
                                                                cb_S_List[idx].CheckedChanged -= sCheck;

                                                                tb_S_List[idx].Value = 0;
                                                                cb_S_List[idx].Checked = false;
                                                                lb_S_List[idx].Text = null;

                                                                tb_S_List[idx].Enabled = false;
                                                                cb_S_List[idx].Enabled = false;
                                                                lb_S_List[idx].Enabled = false;

                                                                logBox.AppendText(string.Format("Event :: Init ^ AcceptSesson { Or exiting one } \n"));
                                                                logBox.AppendText(string.Format("Session [Remove] :: {0}\n", lb_S_List[idx].Text));
                                                                logBox.AppendText(string.Format("State :: {0}\n", NewState));
                                                                logBox.AppendText(string.Format("sID :: {0}\n", sID));
                                                                logBox.AppendText(string.Format("pID :: {0}\n", processsId));
                                                                logBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                                            }
                                                        }
                                                        catch (Exception) { }
                                                        finally
                                                        {
                                                            Taken_S.Remove(idx);
                                                            pIdlist.Remove(processsId);

                                                            try
                                                            {
                                                                var sess = SessionManager.Where(x => x.Key == ses).First().Key;
                                                                if (SessionManager.ContainsKey(sess))
                                                                {
                                                                    sessionList.Remove(SessionManager[sess]);
                                                                    SessionManager.Remove(sess);
                                                                }
                                                            }
                                                            catch (Exception)
                                                            {
                                                                //throw;
                                                            }
                                                        }
                                                    });
                                                #endregion
                                            }

                                        }, pID);
                                } 
                                #endregion
                            }
                        }
                    }
                    catch (Exception)
                    {
                        //throw;
                    }
                    #endregion
                }
            );
        }

        // extract name from IMMDevice
        private string GetName(Vista.IMMDevice device)
        {
            try
            {
                Vista.IPropertyStore Store;
                device.OpenPropertyStore(Vista.EStgmAccess.STGM_READ, out Store);
                int count;
                Store.GetCount(out count);
                var keyList = new Dictionary<Vista.PropertyKey, Vista.PropVariant>();
                for (int i = 0; i < count; i++)
                {
                    Vista.PropertyKey Key;
                    Vista.PropVariant Variant;
                    Store.GetAt(i, out Key);
                    Store.GetValue(ref Key, out Variant);
                    keyList.Add(Key, Variant);
                }

                var keyF = keyList.Keys.Where(
                    k => k.pid == 2 &&
                    k.fmtid.ToString().ToLower() == "a45c254e-df1c-4efd-8020-67d146a850e0".ToLower()).First();
                return keyList[keyF].Value.ToString();
            }
            catch (Exception)
            {
                //throw;
            }


            return null;
        }

        // IAudioSessionControl manger -> call it instead Init(...)
        private void GetLastSession(Vista.IAudioSessionControl session)
        {
            // it seems that some application use many session.
            // and if you take the wrong one.
            // nothing will change [Mute, Volume]
            // so Grab the last will fix the problem

            ++Counter;
            uint PID;
            (session as Vista.IAudioSessionControl2).GetProcessId(out PID);

            int ID = (int)PID;
            if (sessionCheck.Keys.Contains(ID) == false) { sessionCheck.Add(ID, new List<Vista.IAudioSessionControl>()); }
            sessionCheck[ID].Add(session);

            lock (WorkerLock)
            {
                if (Worker)
                {
                    return;
                }
                else
                {
                    Worker = true;

                    ThreadPool.QueueUserWorkItem(
                        delegate
                        {
                            #region Find
                            int tLast = 0;
                            int tFail = 0;

                            while (true)
                            {
                                if (tLast > 0)
                                {
                                    int lastCounter = Counter;
                                    if (tLast == Counter)
                                    {
                                        bool bSuccess = true;

                                        if (Counter != lastCounter)
                                        {
                                            bSuccess = false;
                                            tLast = Counter;
                                            continue;
                                        }

                                        for (int i = 0; i < sessionCheck.Keys.Count; i++)
                                        {
                                            try
                                            {
                                                var key = sessionCheck.Keys.ElementAt(i);
                                                if (key > 0 &&
                                                        sessionCheck[key].Count() > 0)
                                                {
                                                    try { var CheckExist = Process.GetProcessById(key).MainModule.FileName; }
                                                    catch { continue; }

                                                    var index = sessionCheck[key].Count();
                                                    if (index > 0) {
                                                        int Position = index - 1;

                                                        base.Invoke(
                                                            (MethodInvoker)delegate
                                                        {
                                                            string sID;
                                                            (sessionCheck[key][Position] as Vista.IAudioSessionControl2).GetSessionInstanceIdentifier(out sID);

                                                            Vista.AudioSessionState NewState;
                                                            (sessionCheck[key][Position] as Vista.IAudioSessionControl2).GetState(out NewState);

                                                            logBox.AppendText(string.Format("Session [Count] :: {0}\n", sessionCheck[key].Count));
                                                            logBox.AppendText(string.Format("Session [Index] :: {0}\n", "Last"));
                                                            logBox.AppendText(string.Format("State :: {0}\n", NewState));
                                                            logBox.AppendText(string.Format("sID :: {0}\n", sID));
                                                            logBox.AppendText(string.Format("pID :: {0}\n", key));
                                                            logBox.AppendText(string.Format("---- ---- ---- ----\n"));
                                                        });

                                                        ThreadPool.QueueUserWorkItem(Init, sessionCheck[key][Position]);
                                                    }
                                                }
                                            }
                                            catch (Exception)
                                            {
                                                bSuccess = false;
                                                tLast = Counter;
                                                break;
                                            }
                                        }

                                        if (bSuccess)
                                        {
                                            sessionCheck.Clear();
                                            Worker = false;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        tLast = Counter;
                                        Thread.Sleep(250);
                                    }
                                }
                                else
                                {
                                    if (tFail == 5)
                                    {
                                        sessionCheck.Clear();
                                        Worker = false;
                                        break;
                                    }

                                    ++tFail;
                                    tLast = Counter;
                                    Thread.Sleep(250);
                                }
                            }
                            #endregion
                        });
                }
            }
        }
        #endregion
        #region VISTA :: Notification
        public class iAudioSessionNotification : Vista.IAudioSessionNotification
        {
            public delegate int AcceptSessonHandler(Vista.IAudioSessionControl sessionControl);
            public event AcceptSessonHandler AcceptSesson;
            public int OnSessionCreated(Vista.IAudioSessionControl sessionControl)
            {
                try
                {
                    return AcceptSesson(sessionControl);
                }
                catch (Exception)
                {
                    return 1;
                }
            }
        }
        public class AudioEndpointVolumeCallback : Vista.IAudioEndpointVolumeCallback
        {
            private Vista.IMMDevice _device;
            private Vista.IAudioEndpointVolume _Parent;
            public AudioEndpointVolumeCallback(Vista.IAudioEndpointVolume parent, Vista.IMMDevice device)
            {
                _Parent = parent;
                _device = device;
            }

            public event EventHandler<Data> VolumeChanged;
            public class Data : EventArgs
            {
                public bool bMuted;
                public float fMasterVolume;
                public Vista.IMMDevice device;
                public Vista.IAudioEndpointVolume iAudioEndpointVolume;
            }

            /// <summary>
            /// http://msdn.microsoft.com/en-us/library/windows/desktop/dd370799(v=vs.85).aspx
            /// </summary>
            private struct AUDIO_VOLUME_NOTIFICATION_DATA
            {
                public Guid guidEventContext;
                public bool bMuted;
                public float fMasterVolume;
                public uint nChannels;
                public float afChannelVolumes;
            }

            /// <summary>
            /// Pointer to the volume-notification data.
            /// This parameter points to a structure of type AUDIO_VOLUME_NOTIFICATION_DATA.
            /// </summary>
            /// <param name="pNotifyData"></param>
            /// <returns></returns>
            public int OnNotify(IntPtr pNotifyData)
            {
                try
                {
                    AUDIO_VOLUME_NOTIFICATION_DATA DATA = (AUDIO_VOLUME_NOTIFICATION_DATA)Marshal.PtrToStructure(pNotifyData, typeof(AUDIO_VOLUME_NOTIFICATION_DATA));
                    VolumeChanged(this, new Data()
                    {
                        bMuted = DATA.bMuted,
                        fMasterVolume = DATA.fMasterVolume,
                        iAudioEndpointVolume = _Parent,
                        device = _device
                    });
                }
                catch (Exception)
                {
                    //throw;
                }

                return 1;
            }
        }
        public class iAudioSessionEvents : Vista.IAudioSessionEvents
        {
            public delegate int StateChangedHandler(Vista.IAudioSessionEvents sessionEvent, Vista.AudioSessionState NewState);
            public delegate int VolumeChangedHandler(Vista.IAudioSessionEvents sessionEvent, float NewVolume, bool newMute);

            public event VolumeChangedHandler VolumeChanged;
            public event StateChangedHandler StateChanged;

            //public event 
            public int OnDisplayNameChanged(string NewDisplayName, Guid EventContext)
            {
                return 1;
            }

            public int OnIconPathChanged(string NewIconPath, Guid EventContext)
            {
                return 1;
            }

            public int OnSimpleVolumeChanged(float NewVolume, bool newMute, Guid EventContext)
            {
                try
                {
                    return VolumeChanged(this, NewVolume, newMute);
                }
                catch (Exception)
                {
                    return 1;
                    //throw;
                }
            }

            public int OnChannelVolumeChanged(uint ChannelCount, IntPtr NewChannelVolumeArray, uint ChangedChannel, Guid EventContext)
            {
                return 1;
            }

            public int OnGroupingParamChanged(Guid NewGroupingParam, Guid EventContext)
            {
                return 1;
            }

            public int OnStateChanged(Vista.AudioSessionState NewState)
            {
                try
                {
                    return StateChanged(this, NewState);
                }
                catch (Exception)
                {

                    return 1;
                    //throw;
                }
            }

            public int OnSessionDisconnected(Vista.AudioSessionDisconnectReason DisconnectReason)
            {
                return 1;
            }
        }
        public class NotificationClient : Vista.IMMNotificationClient
        {
            private Vista.IMMDeviceEnumerator enumrator;
            public delegate void DeviceAddHandler(Vista.IMMDevice newDevice);
            public delegate void DeviceRemove(Vista.IMMDevice oldDevice);

            public event DeviceAddHandler OnAdd;
            public event DeviceRemove OnRemove;

            public NotificationClient(Vista.IMMDeviceEnumerator enumrator)
            {
                this.enumrator = enumrator;
            }

            public void OnDeviceStateChanged(string deviceId, uint newState)
            {
                return;
            }

            // http://msdn.microsoft.com/en-us/library/windows/desktop/dd371417(v=vs.85).aspx
            public void OnDeviceAdded(string deviceId)
            {
                Vista.IMMDevice device;
                enumrator.GetDevice(deviceId, out device);
                OnAdd(device);
            }

            // http://msdn.microsoft.com/en-us/library/windows/desktop/dd371417(v=vs.85).aspx
            public void OnDeviceRemoved(string deviceId)
            {
                Vista.IMMDevice device;
                enumrator.GetDevice(deviceId, out device);
                OnRemove(device);
            }

            public void OnDefaultDeviceChanged(Vista.EDataFlow dataFlow, Vista.ERole deviceRole, string defaultDeviceId)
            {
                return;
            }

            public void OnPropertyValueChanged(string deviceId, Vista.PropertyKey propertyKey)
            {
                return;
            }
        }
        #endregion
    }
}